﻿
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace WHLRDF.ORM
{
    public partial class AdoRepository
    {
        private const string Cache_Key = "T_ENTITY_AttributeMappingTable_";
        private readonly object locked = new object();
        public ICacheService CacheService
        {
            get
            {
                return CacheHelper.CacheService;
            }
        }
        #region CRUD

        public T GetById<T>(string id) where T : class, new()
        {
            return this.GetById<T>(id, null, true);
        }

        public T GetById<T>(string id, Func<T, T> func) where T : class, new()
        {
            return this.GetById<T>(id, func, true);
        }
        /// <summary>
        /// 获取单类实例
        /// </summary>
        /// <typeparam name="id"></typeparam>
        /// <typeparam name="func"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T GetById<T>(string id, Func<T, T> func, bool isCache = true) where T : class, new()
        {
            if (id == null || string.IsNullOrWhiteSpace(id))
            {
                return default(T);
            }
            var dataProxy = new DataProxy(typeof(T));
            DataParameterCollection dataparam = new DataParameterCollection(this);
            ICriterion criterion = Expression.Eq(dataProxy.PrimaryKeyName, id);
            string sql = string.Format(dataProxy.SelectSql(), " and " + criterion.ToString(ref dataparam));
            var idataReader = this.Reader(sql, dataparam);
            T entity = null;
            try
            {
                if (idataReader.Read())
                {
                    entity = dataProxy.DataReaderToEntity<T>(idataReader);
                }
                if (entity != null && func != null)
                {
                    entity = func(entity);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                idataReader.Close();
            }

            return entity;
        }



        public TEntity Select<TEntity>(ICriterion criterion) where TEntity : class, new()
        {
            var list = this.Query<TEntity>(criterion, null);
            if (list != null && list.Count > 0)
            {
                return list[0];
            }
            return null;
        }

        public TEntity Select<TEntity>(string hql, ICriterion criterion) where TEntity : class, new()
        {
            var list = this.Query<TEntity>(hql, criterion, null);
            if (list != null && list.Count > 0)
            {
                return list[0];
            }
            return null;
        }

        #region 删除
        public bool Delete<T>(T entity) where T : class, new()
        {
            var dataProxy = new DataProxy(typeof(T));
            return Delete<T>(entity,dataProxy);
        }

        public bool Delete<T>(T entity, DataProxy dataProxy) where T : class, new()
        {
            ICriterion criterion = Expression.Eq(dataProxy.PrimaryKeyName, dataProxy.GetPrimaryValue(entity));
            var dataparam = new DataParameterCollection(this);
            string sql = string.Format(dataProxy.DeleteSql(ref dataparam), " and " + criterion.ToString(ref dataparam));
            int i = this.Execute(sql, dataparam);
            return i > 0;
        }

        public bool Delete<T>(ICriterion criterion, bool isupdated = true) where T : class, new()
        {
            var dataProxy = new DataProxy(typeof(T));

            DataParameterCollection dataParam = new DataParameterCollection(this);
            string where = criterion.ToString(ref dataParam);
            if (string.IsNullOrWhiteSpace(where))
            {
                throw new Exception("没有相关查询条件！");
            }
            int i = this.Execute(string.Format(dataProxy.DeleteSql(ref dataParam), " and " + where), dataParam);

            return i > 0;
        }



        public bool Delete<T>(string ids, bool isupdated = true) where T : class, new()
        {
            var dataProxy = new DataProxy(typeof(T));
            var primaryKey = dataProxy.DbFields.Where(x => x.IsPrimaryKey).FirstOrDefault();
            bool isString = true;
            if (primaryKey.ColumnType.ToLower() == "int")
            {
                isString = false;
            }
            object[] deleteIds = ids.Split(new char[] { ',', ';' });
            if (!isString)
            {
                deleteIds = Array.ConvertAll<string, object>(ids.Split(new char[] { ',', ';' }), x => int.Parse(x));
            }
            ICriterion where = Expression.In(dataProxy.PrimaryKeyName, deleteIds);
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string sql = dataProxy.DeleteSql(ref dataParam);
            sql = string.Format(sql, " and " + where.ToString(ref dataParam));
            int i = this.Execute(sql, dataParam);
            //action.RemoveCacheEntity(typeof(T), deleteIds);
            return i > 0;
        }
        #endregion

        #region SaveOrUpdate
        public bool SaveOrUpdate<T>(T entity) where T : class, new()
        {
            string strError = "";
            var dataProxy = new DataProxy(typeof(T));
            return this.SaveOrUpdate<T>(entity, dataProxy, ref strError);
        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="strError"></param>
        /// <returns></returns>
        public bool SaveOrUpdate<T>(T entity, ref string strError) where T : class, new()
        {
            var dataProxy = new DataProxy(typeof(T));
            return this.SaveOrUpdate<T>(entity, dataProxy, ref strError);
        }


        private bool SaveOrUpdate<T>(T entity, DataProxy dataProxy, ref string strError) where T : class, new()
        {
            EntityState entityState = dataProxy.IsUpdate(entity);
            
            if (entityState == EntityState.None)
            {
                entityState = EntityState.Add;
                if (dataProxy.IsExist(this, entity))
                {
                    entityState = EntityState.Update;
                }
            }
            if (entityState == EntityState.Add)
            {
                return this.Insert<T>(entity, dataProxy, ref strError);
            }
            else if (entityState == EntityState.Delete)
            {
                return this.Delete<T>(entity, dataProxy);
            }
            else
            {
                return this.Update<T>(entity, dataProxy, ref strError);
            }
        }

        #endregion

        #region Update
        public bool Update<T>(T entity) where T : class, new()
        {
            string strError = "";

            return this.Update<T>(entity, ref strError);
        }
        public bool Update<T>(T entity, ref string strError) where T : class, new()
        {
            var action = new DataProxy(typeof(T));
            return this.Update<T>(entity, action, ref strError);
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lstEntity"></param>
        /// <param name="strError"></param>
        /// <returns></returns>
        public bool BatchUpdate<T>(List<T> lstEntity, ref string strError) where T : class, new()
        {
            if (lstEntity != null && lstEntity.Count > 0)
            {
                var action = new DataProxy(typeof(T));
                foreach (var entity in lstEntity)
                {
                    if (!this.Update<T>(entity, action, ref strError))
                    {
                        return false;
                    }
                }

            }
            return true;
        }
        private bool Update<T>(T entity, DataProxy dataProxy, ref string strError) where T : class, new()
        {
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string sql = dataProxy.UpdateSql(entity, ref dataParam, ref strError);
            if (string.IsNullOrWhiteSpace(sql))
            {
                return true;
            }
            var result = this.Execute(sql, dataParam);
            if (result <= 0)
            {
                throw new Exception(entity.ToJson() + "更新失败，原因可能为未找到该数据！");
            }
            return result > 0;
        }

        /// <summary>
        /// 通过查询条件批量更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <param name="criterion"></param>
        /// <returns></returns>
        public bool Update<TEntity>(TEntity entity, ICriterion criterion) where TEntity : class, new()
        {
            DataProxy dataProxy = new DataProxy(typeof(TEntity));
            string strError = "";
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string sql = dataProxy.UpdateSql(entity, criterion, ref dataParam, ref strError);
            if (string.IsNullOrWhiteSpace(sql))
            {
                return true;
            }
            var result = this.Execute(sql, dataParam);

            return result > 0;
        }
        #endregion

        #region Insert 
        public bool Insert<T>(T entity) where T : class, new()
        {
            string strError = "";
            return this.Insert<T>(entity, ref strError);
        }
        public bool Insert<T>(T entity, ref string strError) where T : class, new()
        {
            var action = new DataProxy(typeof(T));
            return this.Insert<T>(entity, action, ref strError);
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lstEntity"></param>
        /// <param name="strError"></param>
        /// <returns></returns>
        public bool BatchInsert<T>(List<T> lstEntity, ref string strError) where T : class, new()
        {
            if (lstEntity != null && lstEntity.Count > 0)
            {
                var action = new DataProxy(typeof(T));
                foreach (var entity in lstEntity)
                {
                    if (!this.Insert<T>(entity, action, ref strError))
                    {
                        return false;
                    }
                }

            }
            return true;
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="action"></param>
        /// <param name="strError"></param>
        /// <returns></returns>
        private bool Insert<T>(T entity, DataProxy dataProxy, ref string strError)
        {
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string sql = dataProxy.InsertSql(this, entity, ref dataParam);
            int result = 0;
            if (dataProxy.Identifier)
            {
                result = this.Scalar(sql, dataParam).ToInt();
                if (result > 0)
                {
                    dataProxy.SetValue(entity, dataProxy.PrimaryKeyName, result);
                }
            }
            else
            {
                result = this.Execute(sql, dataParam);
            }
            return result > 0;
        }
        #endregion


        /// <summary>
        /// 批量保存 事务调用方法前自己开启
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lstData"></param>
        public bool BatchSave<T>(List<T> lstData) where T : class, new()
        {

            if (lstData != null && lstData.Count > 0)
            {
                var dataProxy = new DataProxy(typeof(T));
                string strError = "";
                foreach (var item in lstData)
                {
                    this.SaveOrUpdate<T>(item, dataProxy, ref strError);
                }
            }
            return true;

        }

        #endregion

        public List<T> Query<T>(ICriterion criterion, Order order) where T : class, new()
        {
            var dataProxy = new DataProxy(typeof(T));

            string sql = _provider.Database.GetSelectSql(dataProxy.TableName, dataProxy.QueryFieldBuilder, dataProxy.TableAttr.IsDeleted);
            if (string.IsNullOrWhiteSpace(sql))
                return null;
            return this.Query<T>(sql, criterion, order);
        }
        public List<T> Query<T>(string sql, ICriterion criterion) where T : class, new()
        {
            return this.Query<T>(sql, criterion, null);
        }
        public List<T> Query<T>(string sql, ICriterion criterion, Order order) where T : class, new()
        {
            List<T> lstT = new List<T>();

            if (string.IsNullOrWhiteSpace(sql))
                return null;
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string where = (criterion != null) ? criterion.ToString(ref dataParam) : "";
            if (!string.IsNullOrWhiteSpace(where))
            {
                where = " and " + where;
            }
            if (order != null)
            {
                where += " order by " + order.ToString();
            }
            sql = string.Format(sql, where);
            return GetReader<T>(sql, dataParam);
        }
        public List<T> Query<T>(ICriterion criterion) where T : class, new()
        {
            //this.Close(IsBeginTransaction());
            return this.Query<T>(criterion, null);
        }
        public List<T> Query<T>(ICriterion criterion, Order order, int pageindex, int pageSize, ref int recordCount) where T : class, new()
        {
            DataProxy dataProxy = new DataProxy(typeof(T));
            List<T> lstT = new List<T>();
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string where = (criterion != null) ? criterion.ToString(ref dataParam) : "";
            string cacheKey = MD5Helper.MD5Encrypt(dataParam.ToJson());
            if (pageindex > 0)
            {
                recordCount = this.RecordCount(_provider.Database.GetRecordCountSql(dataProxy.TableName), criterion,false);
            }
            string sql = _provider.Database.QueryPage(string.Format(_provider.Database.GetSelectSql(dataProxy.TableName, dataProxy.QueryFieldBuilder, dataProxy.TableAttr.IsDeleted),""), new Order[] { order }, pageindex, pageSize);
            if (!string.IsNullOrWhiteSpace(where))
            {
                where = " and " + where;
            }
            sql = string.Format(sql, where);

            return GetReader<T>(sql, dataParam);
        }

        /// <summary>
        /// 通过sql查询获取分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hql">样例:select * from table where 1=1 sql后面一定要带where 1=1</param>
        /// <param name="criterion"></param>
        /// <param name="order"></param>
        /// <param name="pageindex"></param>
        /// <param name="pageSize"></param>
        /// <param name="recordCount"></param>
        /// <returns>支持entitybase  Dictionary<string, object></returns>
        public List<T> Query<T>(string hql, ICriterion criterion, Order order, int pageindex, int pageSize, ref int recordCount) where T : class, new()
        {
            List<T> lstT = new List<T>();
            if (pageindex > 0)
            {
                recordCount = this.RecordCount(hql, criterion);
                if (recordCount <= 0)
                {
                    return lstT;
                }
            }
            string sql = _provider.Database.QueryPage(hql, new Order[] { order }, pageindex, pageSize);
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string where = (criterion != null) ? criterion.ToString(ref dataParam) : "";
            if (!string.IsNullOrWhiteSpace(where))
            {
                sql = string.Format(sql, " and " + where);
            }
            else
            {
                sql = string.Format(sql, "");
            }
            sql = string.Format(sql, where);


            return this.GetReader<T>(sql, dataParam);
        }

        public LigerGrid Query<T>(string hql, LigerGrid ligerGrid, ICriterion criterion) where T : class, new()
        {
            int recordCount = 0;
            var WhereExpression = ligerGrid.WhereExpression;
            if (WhereExpression != null)
            {
                criterion = Expression.And(criterion, WhereExpression);
            }
            if (string.IsNullOrWhiteSpace(ligerGrid.sortOrder))
            {
                ligerGrid.sortOrder = "desc";
            }
            if (string.IsNullOrWhiteSpace(ligerGrid.sortName))
            {
                ligerGrid.sortName = EntityBase.__LastModifyDate;
            }
            Order order = (ligerGrid.sortOrder.ToLower() == "asc") ? Order.Asc(ligerGrid.sortName) : Order.Desc(ligerGrid.sortName);
            ligerGrid.records = 0;
            if (ligerGrid.pageSize > 0)
            {
                var result = Query<T>(hql, criterion, order, ligerGrid.pageIndex, ligerGrid.pageSize, ref recordCount);

                if (result == null)
                {
                    ligerGrid.Rows = new List<T>();
                }
                else
                {
                    ligerGrid.records = result.Count;
                    ligerGrid.Rows = result;
                }
            }
            else
            {
                var result = Query<T>(hql, criterion, order);
                ligerGrid.Rows = result;
                ligerGrid.records = result.Count;
            }
            ligerGrid.Total = recordCount;
            return ligerGrid;

        }
        public LigerGrid Query<T>(LigerGrid ligerGrid, ICriterion criterion) where T : class, new()
        {
            int recordCount = 0;
            var WhereExpression = ligerGrid.WhereExpression;
            if (WhereExpression != null)
            {
                criterion = Expression.And(criterion, WhereExpression);
            }
            Order order = (ligerGrid.sortOrder.ToLower() == "asc") ? Order.Asc(ligerGrid.sortName) : Order.Desc(ligerGrid.sortName);
            if (ligerGrid.pageSize > 0)
            {
                var result = Query<T>(criterion, order, ligerGrid.pageIndex, ligerGrid.pageSize, ref recordCount);
                if (result == null)
                {
                    ligerGrid.Rows = new List<T>();
                }
                else
                {
                    ligerGrid.records = result.Count;
                    ligerGrid.Rows = result;
                }
            }
            else
            {
                var result = Query<T>(criterion, order);
                ligerGrid.Rows = result;
                if (result != null)
                {
                    ligerGrid.records = result.Count;
                }

            }

            ligerGrid.Total = recordCount;
            return ligerGrid;
        }

        /// <summary>
        /// 获取总数
        /// </summary>
        /// <param name="hql"></param>
        /// <param name="criterion"></param>
        /// <param name="createSql">是否需要重建Sql</param>
        /// <returns></returns>
        public int RecordCount(string hql, ICriterion criterion, bool createSql = true)
        {
            string sql = _provider.Database.RecordCount(hql, createSql);
            if (string.IsNullOrWhiteSpace(sql))
                return 0;
            DataParameterCollection dataParam = new DataParameterCollection(this);
            string where = (criterion != null) ? criterion.ToString(ref dataParam) : "";
            if (!string.IsNullOrWhiteSpace(where))
            {
                where = " and " + where;
            }
            sql = string.Format(sql, where);

            return this.Scalar(sql, dataParam).ToInt();
        }




        #region 获取数据库中的值
        public List<Dictionary<string, object>> GetTable(string dbName)
        {
            string sql = _provider.Database.GetTable(dbName);
            return this.Query<Dictionary<string, object>>(sql, null);
        }
        public List<Dictionary<string, object>> GetView(string dbName)
        {
            string sql = _provider.Database.GetView(dbName);
            return this.Query<Dictionary<string, object>>(sql, null);
        }
        public List<Dictionary<string, object>> GetDbColumn(string dbName, string dbServerName, bool isTable)
        {
            string sql = _provider.Database.GetDbColumn(dbName, dbServerName, isTable);
            return this.Query<Dictionary<string, object>>(sql, null);
        }

        public LigerGrid GetSource(string dbName, LigerGrid grid)
        {
            string sql = _provider.Database.GetSource(dbName);
            int reCordCount = 0;
            Order order = (string.IsNullOrWhiteSpace(grid.sortOrder) ? null : ((grid.sortOrder.ToLower() == "asc") ? Order.Asc(grid.sortName) : Order.Desc(grid.sortName)));
            var result = this.Query<Dictionary<string, object>>(sql, grid.WhereExpression, order, grid.pageIndex, grid.pageSize, ref reCordCount);
            grid.Rows = result;
            if (result != null)
            {
                grid.records = result.Count;
            }
            grid.Total = reCordCount;
            return grid;
        }
        /// <summary>
        /// 生成创建表sql
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="dbColumns"></param>
        /// <returns></returns>
        public string CreateTable(string tableName, List<DbColumnAttribute> dbColumns)
        {
            return _provider.Database.CreateTable(tableName, dbColumns);
        }

        /// <summary>
        /// 创建列
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="columnItem"></param>
        /// <returns></returns>
        public string AddColumn(string tableName, DbColumnAttribute columnItem)
        {
            return _provider.Database.AddColumn(tableName, columnItem);
        }
        /// <summary>
        /// 禁用自增
        /// </summary>
        /// <returns></returns>
        public bool Identity_Disabled(string tableName)
        {
            string hql = _provider.Database.Identity_Disabled(tableName);
            if (!string.IsNullOrWhiteSpace(hql))
            {
                this.Execute(hql);
            }

            return true;
        }

        /// <summary>
        /// 启用自增
        /// </summary>
        /// <returns></returns>
        public bool Identity_Enable(string tableName)
        {
            string hql = _provider.Database.Identity_Enable(tableName);
            if (!string.IsNullOrWhiteSpace(hql))
            {
                this.Execute(hql);
            }

            return true;
        }
        #endregion

        #region entityBinding

        public List<T> GetReader<T>(string sql, DataProxy dataProxy, DataParameterCollection dataParam) where T : new()
        {
            List<T> lstT = new List<T>();
            lock (locked)
            {
                var reader = this.Reader(sql, dataParam);
                try
                {
                    while (reader.Read())
                    {
                        lstT.Add(dataProxy.DataReaderToEntity<T>(reader));
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    reader.Close();
                }
            }
            return lstT;
        }
        public List<T> GetReader<T>(string sql, DataParameterCollection dataParam) where T : new()
        {
            List<T> lstT = new List<T>();
            lock (locked)
            {
                var reader = this.Reader(sql, dataParam);
                try
                {
                    while (reader.Read())
                    {
                        lstT.Add(DataProxy.ReaderToEntity<T>(reader));
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    reader.Close();
                }
            }
            return lstT;
        }

        #endregion
        public DbParameter MakeOutParam(string paramName, DbType DbType, int Size)
        {
            return _provider.Database.MakeOutParam(paramName, DbType, Size);
        }

        public DbParameter MakeInParam(string paramName, DbType DbType, int Size, object Value)
        {
            return _provider.Database.MakeInParam(paramName, DbType, Size, Value);
        }

        public DbParameter MakeParam(string paramName, DbType DbType, Int32 Size, ParameterDirection Direction, object Value)
        {
            return _provider.Database.MakeParam(paramName, DbType, Size, Direction, Value);
        }
        /// <summary>
        /// 更改字段描述
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="columnName"></param>
        /// <param name="description"></param>
        /// <param name="isInsert"></param>
        /// <returns></returns>
        public string UpdateDescriptionSql(string tableName, string columnName, string description, bool isAdd)
        {
            return _provider.Database.UpdateDescriptionSql(tableName, columnName, description, isAdd);
        }

        /// <summary>
        /// 判断描述是否存在
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="columnName">字段名</param>
        /// <returns></returns>
        public string ExistDescriptionSql(string tableName, string columnName)
        {
            return _provider.Database.ExistDescriptionSql(tableName, columnName);
        }


    }
}
